package org.artifact.xls;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateConfig.ResourceMode;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import lombok.Builder;
import org.artifact.xls.convert.file.AbstractFileConvert;
import org.artifact.xls.convert.file.CsvFileConvert;
import org.artifact.xls.convert.file.LuaFileConvert;

import java.io.*;
import java.util.*;

@Builder
public class ExcelExport {
    private static final Log log = LogFactory.get(ExcelExport.class);
    /**
     * 模板组
     */
    private TemplateConfig templateConfig;

    /** 生成的源码路径 */
//	private String sourcePath;

    /**
     * 生成源码的包名称
     */
    private String packageName;

    /**
     * 设计文件路径
     */
    private String designSourcePath;

    /**
     * 输出目录
     */
    private String outputPath;

    /**
     * 继承关系
     */
    private Map<String, String> exts = new HashMap<>();


    public static final boolean SHEET_MODE = true;

    /**
     * 使用默认模板组
     *
     * @return
     */
    public void useDefaultGroupTemplate() {
        this.templateConfig = new TemplateConfig();
        this.templateConfig.setCharset(CharsetUtil.CHARSET_UTF_8);
        this.templateConfig.setResourceMode(ResourceMode.CLASSPATH);
    }

    public void exec() throws Exception {
        if (this.templateConfig == null) {
            useDefaultGroupTemplate();
        }

        if (StrUtil.isBlank(outputPath) || StrUtil.isBlank(packageName) || designSourcePath == null) {
            throw new IllegalStateException("请检查配置");
        }

        check();

//		verify();

        execute();

        completeInfo();
    }

    private void execute() {
        TemplateEngine engine = TemplateUtil.createEngine(this.templateConfig);

        List<File> files = FileUtil.loopFiles(designSourcePath, new FileFilter() {
            @Override
            public boolean accept(File file) {
                if (FileUtil.pathEndsWith(file, "xlsx")) {
                    return true;
                } else if (FileUtil.pathEndsWith(file, "xls")) {
                    return true;
                } else if (FileUtil.pathEndsWith(file, "xlsm")) {
                    return true;
                } else if (FileUtil.pathEndsWith(file, "yml")) {
                    return true;
                } else {
                    return false;
                }
            }
        });


        Map<String, ExcelBean> beans = getExcelBeans(files);
        // 设置继承
        for (Map.Entry<String, String> entry : exts.entrySet()) {
            beans.get(entry.getKey()).setExt(beans.get(entry.getValue()));
        }

        FileUtil.del(outputPath + File.separator + "script");

        // 生成C#代码
        {
            Template template = engine.getTemplate("ClientConfigLoader_sjs.btl");
            Map<String, Object> bindingMap = new HashMap<>();
            bindingMap.put("structs", beans.values());
            bindingMap.put("exts", exts);
            String pathname = outputPath + File.separator + "script" + File.separator + "c#" + File.separator + "ClientConfigLoader.cs";
            render(pathname, template, bindingMap);

            for (Map.Entry<String, ExcelBean> entry : beans.entrySet()) {
                template = engine.getTemplate("CsBeanConfigTemplate.btl");
                bindingMap = new HashMap<>();
                bindingMap.put("struct", entry.getValue());
                bindingMap.put("exts", exts);
                pathname = outputPath + File.separator + "script" + File.separator + "c#" + File.separator + entry.getKey() + "Config.cs";
                render(pathname, template, bindingMap);
            }
        }


        // 生成Java代码
        {
            Template template = engine.getTemplate("JavaConfigLoader_helper.btl");
            Map<String, Object> bindingMap = new HashMap<>();
            bindingMap.put("structs", beans.values());
            bindingMap.put("packageName", packageName);
            bindingMap.put("exts", exts);
            String pathname = outputPath + File.separator + "script" + File.separator + "java" + File.separator + "JavaConfigLoader.java";
            render(pathname, template, bindingMap);

            for (Map.Entry<String, ExcelBean> entry : beans.entrySet()) {
                template = engine.getTemplate("JavaBeanConfigTemplate.btl");
                bindingMap = new HashMap<>();
                bindingMap.put("struct", entry.getValue());
                bindingMap.put("packageName", packageName);
                bindingMap.put("exts", exts);
                pathname = outputPath + File.separator + "script" + File.separator + "java" + File.separator + entry.getKey() + "Config.java";
                render(pathname, template, bindingMap);
            }
        }
        // 生成数据文件
        FileUtil.del(outputPath + File.separator + "data");
        {
            List<AbstractFileConvert> converts = new ArrayList<>();
            converts.add(new CsvFileConvert());
            converts.add(new LuaFileConvert());
            for (File file : files) {
                String type = FileUtil.getType(file);
                String fileoutpath = outputPath + File.separator + "data";
                for (AbstractFileConvert convert : converts) {
                    switch (type) {
                        case "yml":
                            convert.convertYml(file, fileoutpath);
                            break;
                        case "xls":
                        case "xlsx":
                        case "zip":
                            convert.convertXlsx(file, fileoutpath);
                            break;
                    }
                }
            }
            for (AbstractFileConvert convert : converts) {
                convert.writeI18nFile(outputPath + File.separator + "data");
            }
        }

    }

    private void render(String path, Template template, Map<String, Object> bindingMap) {
        File file = FileUtil.newFile(path);
        FileOutputStream fis = null;
        OutputStreamWriter osw = null;
//		FileWriter fileWriter = null;
        try {
//			fileWriter = new FileWriter(new File(path));
//			File file = FileUtil.newFile(path);
            FileUtil.mkParentDirs(file);
//			fileWriter = new FileWriter(file);

            fis = new FileOutputStream(file);
            osw = new OutputStreamWriter(fis, "UTF-8");
            template.render(bindingMap, osw);
            osw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (osw != null) {
                try {
                    osw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void check() {

        if (!FileUtil.isDirectory(designSourcePath)) {
            throw new IllegalStateException("不是目录");
        }

        File file = new File(outputPath);
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * 成功打印信息
     */
    public static void completeInfo() {
        System.out.println("*********************************************");
        System.out.println("*                                           *");
        System.out.println("**********代码生成完成-请刷新项目！**********");
        System.out.println("*                                           *");
        System.out.println("*********************************************");
        System.exit(0);
    }


    public Map<String, ExcelBean> getExcelBeans(List<File> files) {
        Map<String, ExcelBean> beans = new LinkedHashMap<>();
        for (File file : files) {
            beans.putAll(getExcelBeans(file));
        }
        return beans;
    }

//    public static void main(String[] args) {
//        FileUtil.getType(FileUtil.file("D:\\WorkSVN\\Public\\配置表\\Config\\Excel\\战斗相关\\J_技能数据表.xlsm"));
//    }

    public Map<String, ExcelBean> getExcelBeans(File file) {
        Map<String, ExcelBean> beans = new LinkedHashMap<>();
        String type = FileUtil.getType(file);
//        log.info("File Name = {},File Type = {}",file.getName(),type);
        if (!type.equals("xls") && !type.equals("xlsx") && !type.equals("zip")) {
            return beans;
        }

        ExcelReader reader = ExcelUtil.getReader(file);

        reader.setIgnoreEmptyRow(true);
        if (SHEET_MODE) {
            List<String> sheetNames = reader.getSheetNames();
            for (String sheetName : sheetNames) {
                reader.setSheet(sheetName);
                String[] strs = StrUtil.split(sheetName, "|");
                if (strs.length != 2) {
                    continue;
                }
                ExcelBean bean = createExeclBean(StrUtil.upperFirst(strs[0]), strs.length == 2 ? strs[1] : "", reader);
                beans.put(bean.getName(), bean);
            }
        } else {
            String fileName = FileUtil.mainName(file);
            String[] strs = StrUtil.split(fileName, "|");
            if (strs.length != 2) {
                return beans;
            }
            ExcelBean bean = createExeclBean(StrUtil.upperFirst(strs[0]), strs.length == 2 ? strs[1] : "", reader);
            beans.put(bean.getName(), bean);
        }
        return beans;
    }


    private ExcelBean createExeclBean(String tableName, String tableRemark, ExcelReader reader) {
        log.debug("Create Struct {}", tableName);
        ExcelBean excelBean = new ExcelBean();
        excelBean.setName(tableName);
        excelBean.setRemark(tableRemark);
        // 设置继承
//		excelBean.setExt(exts.getOrDefault(tableName,""));
        // 字段名称
        List<Object> fieldNames = reader.readRow(0);
        // 字段类型
        List<Object> fieldTypes = reader.readRow(1);
        // 备注
        List<Object> fieldRemarks = reader.readRow(2);
        // 标识
        List<Object> fieldTags = reader.readRow(3);

        int columnCount = reader.getColumnCount();
        for (int i = 0; i < columnCount; i++) {
            if (i >= fieldTags.size() || fieldTags.get(i) == null) {
                // 空列
                continue;
            }
            ExcelField excelField = new ExcelField();
            excelField.setName(StrUtil.lowerFirst(fieldNames.get(i).toString()));
            excelField.setType(new ExcelFieldType(fieldTypes.get(i).toString()));
            excelField.setRemark(fieldRemarks.get(i).toString());
            excelField.setTag(fieldTags.get(i).toString());
            if (StrUtil.isEmpty(excelField.getTag()) || StrUtil.contains(excelField.getTag(), "n")) {
                // 策划字段
                continue;
            }
            excelBean.getFields().put(excelField.getName(), excelField);
        }

        return excelBean;
    }
}
